﻿#include "MirStatusConnection.h"
#include "../Settings.h"

using namespace Server::MirEnvir;

namespace Server::MirNetwork
{

    Server::MirEnvir::Envir *MirStatusConnection::getEnvir()
    {
        return Envir::getMain();
    }

    Server::MessageQueue *MirStatusConnection::getMessageQueue()
    {
        return MessageQueue::getInstance();
    }

    bool MirStatusConnection::getDisconnecting() const
    {
        return _disconnecting;
    }

    void MirStatusConnection::setDisconnecting(bool value)
    {
        if (_disconnecting == value)
        {
            return;
        }
        _disconnecting = value;
        TimeOutTime = getEnvir()->getTime() + 500;
    }

    MirStatusConnection::MirStatusConnection(TcpClient *client)
    {
        try
        {
//C# TO C++ CONVERTER TODO TASK: There is no C++ equivalent to 'ToString':
            IPAddress = client->Client->RemoteEndPoint->ToString().Split(':')[0];

            _client = client;
            _client->NoDelay = true;

            TimeConnected = getEnvir()->getTime();
            TimeOutTime = TimeConnected + Settings::TimeOut;
            Connected = true;
        }
        catch (const std::runtime_error &ex)
        {
            getMessageQueue()->Enqueue(ex);
        }
    }

    void MirStatusConnection::BeginSend(std::vector<unsigned char> &data)
    {
        if (!Connected || data.empty())
        {
            return;
        }

        try
        {
            _client->Client->BeginSend(data, 0, data.size(), SocketFlags::None, [&] (System::IAsyncResult ar) {SendData(ar);}, std::any());
        }
        catch (...)
        {
            setDisconnecting(true);
        }
    }

    void MirStatusConnection::SendData(IAsyncResult *result)
    {
        try
        {
            _client->Client->EndSend(result);
        }
        catch (...)
        {
        }
    }

    void MirStatusConnection::Process()
    {
        try
        {
            if (_client == nullptr || !_client->Connected)
            {
                Disconnect();
                return;
            }

            if (getEnvir()->getTime() > TimeOutTime || getDisconnecting())
            {
                Disconnect();
                return;
            }


            if (getEnvir()->getTime() > NextSendTime)
            {
                NextSendTime = getEnvir()->getTime() + 10000;
                std::string output = StringHelper::formatSimple("c;/NoName/{0}/CrystalM2/{1}//;", getEnvir()->getPlayerCount(), Assembly::GetCallingAssembly()->GetName()->Version);

                BeginSend(Encoding::ASCII->GetBytes(output));
            }
        }
        catch (const std::runtime_error &ex)
        {
            getMessageQueue()->Enqueue(ex);
        }
    }

    void MirStatusConnection::Disconnect()
    {
        try
        {
            if (!Connected)
            {
                return;
            }

            Connected = false;

            {
                std::scoped_lock<std::mutex> lock(getEnvir()->StatusConnections);
                getEnvir()->StatusConnections.Remove(this);
            }

            if (_client != nullptr)
            {
                _client->Client->Dispose();
            }
            _client = nullptr;
        }
        catch (const std::runtime_error &ex)
        {
            getMessageQueue()->Enqueue(ex);
        }
    }

    void MirStatusConnection::SendDisconnect()
    {
        setDisconnecting(true);
    }
}
